#include "ringbuffer.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>



RingBuffer::RingBuffer()
{
    m_buffer = nullptr;
    m_maxSize = 0;
    m_mask = 0;
    m_unit_size = 0;

    clear();
}

RingBuffer::~RingBuffer()
{
    if (m_buffer)
    {
        free(m_buffer);
        m_buffer = nullptr;
    }
}


/**
 * @brief setBufferSizePower 设置2的"size"次幂（即2^size）* m_unit_size大小的缓存
 * @param size
 * eg. 2^16=64K; 2^17=128K; 2^20=1M; 2^26=64M
 * @param unit_size
 *          单个存储单元的大小, 如是字节:1, 指针:sizeof(void*), 其它:sizeof(uint_type)
 * @return 0：内存分配成功；
 *         <0:内存分配失败；
 * @note:  限制最大可分配内存64M * m_unit_size, 即size的最大可用值为26. 太大的缓存空间可能会导致分配失败
 */
int RingBuffer::setBufferSizePower(uint8_t size, uint32_t uint_size)
{
    if (size <= 0)
        return -1;

    if (size > 26)
        return -2;

    if (m_maxSize != 0)
        return -3;

    uint32_t maxSize = 1 << size;
    m_buffer = malloc(maxSize * uint_size);
    if (!m_buffer)
        return -4;
    
    memset(m_buffer, 0, maxSize * uint_size);//此行只是为了方便测试, 实际使用时如果考滤效率可以屏蔽掉

    m_maxSize = maxSize;
    m_mask = m_maxSize - 1;
    m_unit_size = uint_size;

    return 0;
}

/**
 * @brief getBufferSize 获取缓冲区大小
 * @return
 */
int RingBuffer::getBufferSize()
{
    return m_maxSize - 1;
}

/**
 *------------------------------------------------------------------------
 * L的计算参考：getFreeSize()
 * 缓存区中数据大小：N
 *  L + N = M-1
 *  N = M-1 - L
 *  N = M-1 - (R-W+M-1)%M
 *  N = M-1 - (R-W+M-1)%M
 * @brief 获取缓冲区中的可用数据大小
 * @return
 */
uint32_t RingBuffer::getDataSize()
{
    std::lock_guard<std::mutex> locker(m_mutex);

    return m_maxSize - 1 - (m_pr - m_pw + m_maxSize - 1) & m_mask;
}


/**
 *
 *------------------------------------------------------------------------
 *剩余空间：
 *1) R=W, L=M
 *2) R>W, L=R-W
 *3) R<W, L=R-W+M
 *综合3种情况：
 *        L=(R-W+M)%M
 *考滤满情况，必需要空余一个存储单位(Byte):
 *        L=(R-W+M-1)%M
 *
 * ----------

 * @brief freeSize 获取缓冲区中空闲空间大小
 * @return
 */
uint32_t RingBuffer::getFreeSize()
{
    std::lock_guard<std::mutex> locker(m_mutex);

    return (m_pr - m_pw + m_maxSize - 1) & m_mask;
}


/**
 * @brief clear清空缓冲区
 */
void RingBuffer::clear()
{
    std::lock_guard<std::mutex> locker(m_mutex);

    m_pr = 0;
    m_pw = 0;
}


/**
 *
 * eg.4 W>R的情况
 * 0 1                         pM=Max-1=m_mask
 * [_|_|_|*|*|*****|*|*|_|_|_|_|_]Max
 *       R             W
 *
 * eg.5 W<R的情况
 * 0 1 2                     pM=Max-1=m_mask
 * [*|*|*|*|*|_|_____|_|*|*|*|*]Max
 *           W         R
 *
 * @brief readUnit 非阻塞读取, 为了一次性成功读取所需数据，读取前可使用getDataSize()
 *        确定是否有足够的数据
 * @param buffer 存放位置
 * @param length 预读取长度
 * @return >=0, 实际读取长度
 *         <0, 参数错误
 */    
int RingBuffer::read(void *buffer, uint32_t length)
{
    if (!buffer)
        return -1;

    uint32_t dataSize = getDataSize();
    if (length < dataSize)
        dataSize = length;

    std::lock_guard<std::mutex> locker(m_mutex);//不能加在getDataSize()之前,会导致死锁
    if (m_pr + dataSize <= m_mask)//未超缓冲末尾
    {
        memcpy(buffer, (uint8_t*)m_buffer + m_pr * m_unit_size, dataSize * m_unit_size);
    }
    else
    {
        int sizeEnd = m_mask - m_pr + 1;
        int sizeStart = dataSize - sizeEnd;
        memcpy(buffer, (uint8_t*)m_buffer + m_pr * m_unit_size, sizeEnd * m_unit_size);
        memcpy((uint8_t*)buffer + sizeEnd * m_unit_size, m_buffer, sizeStart * m_unit_size);
    }

    m_pr = (m_pr + dataSize) & m_mask;
    return dataSize;
}

/**
 * @brief writePtr 非阻塞写入, 为了一次性成功写入所有数据，读取前可使用getFreeSize()
 *        确定是否有足够的空闲空间
 * @param buffer 待写入数据
 * @param length 待写入长度
 * @return >=0, 实际写入长度
 *         < 0, 参数错误
 */
int RingBuffer::write(void* buffer, uint32_t length)
{
    if (!buffer)
        return -1;

    uint32_t freeSize = getFreeSize();
    if (length >freeSize)
        length = freeSize;


    std::lock_guard<std::mutex> locker(m_mutex);//不能加在getFreeSize()之前,会导致死锁
    if (m_pw + length <= m_mask)
    {
        memcpy((uint8_t*)m_buffer + m_pw * m_unit_size, buffer, length * m_unit_size);
    }
    else
    {
        int endSize = m_mask - m_pw + 1;
        int startSize = length - endSize;
        memcpy((uint8_t*)m_buffer + m_pw * m_unit_size, buffer, endSize * m_unit_size);
        memcpy(m_buffer, (uint8_t*)buffer + endSize * m_unit_size, startSize * m_unit_size);
    }
    m_pw = (m_pw + length) & m_mask;

    return length;
}


void RingBuffer::printBytes(uint32_t start, uint32_t length, uint32_t lineLength)
{
    if (0 == lineLength)
    {
        lineLength = 16;
        printf(" 0 1 2 3 4 5 6 7     8 9 a b c d e f\n");
        printf("------------------------------------");
    }
    for (uint32_t i=0; i<length; i++)
    {
        if (0 == i%lineLength)
            printf("\n");
        if (lineLength/2 == i%lineLength)
            printf("    ");
        printf(" %c", *((uint8_t*)m_buffer + start + i));
    }
    printf("\n");
    fflush(stdout);
}

void RingBuffer::printBytesHex(uint32_t start, uint32_t length, uint32_t lineLength)
{
    if (0 == lineLength)
    {
        lineLength = 16;
        printf("\n 0  1  2  3  4  5  6  7       8  9  a  b  c  d  e  f\n");
        printf("-------------------------------------------------------");
    }
    for (uint32_t i=0; i<length; i++)
    {
        if (0 == i%lineLength)
            printf("\n");

        if (lineLength/2 == i%lineLength)
            printf("    ");

        printf(" %02X", *((uint8_t*)m_buffer + start + i));
    }
    printf("\n");
    fflush(stdout);
}

void RingBuffer::printTestPtr(int length, test_t** test)
{
    if(0 == test)
    {
        test = (test_t**)m_buffer;
    }
    for (int i=0; i<length; i++)
    {
        printf("%02d\t", i);
    }
    printf("\n");
    for (int i=0; i<length; i++)
    {
        if (test[i] != 0)
            printf("%s\t", test[i]->name);
        else
            printf("null\t");
    }
    printf("\n");
}

void RingBuffer::printTestStruct(int length, test_t* test)
{
    if(0 == test)
    {
        test = (test_t*)m_buffer;
    }
    for (int i=0; i<length; i++)
    {
        printf("%02d\t", i);
    }
    printf("\n");
    for (int i=0; i<length; i++)
    {
        printf("%s\t", test[i].name);
    }
    printf("\n");
}



void RingBuffer::testByte()
{
    int ret = 0;
    RingBuffer buffer;
    //设置存储单元为1Byte, 2^5=32个存储单元共1Byte * 32 = 32Bytes 
    if (0 != (ret = buffer.setBufferSizePower(5, 1)))
    {
        printf("set buffer size failed, ret:%d\n", ret);
    }

    char wb[] = "0123456789abcdef0";
    printf("buffer size:%d\n", buffer.getBufferSize());

    printf("will write 17 byte:%s \n", wb);
    ret = buffer.write(wb, 17);
    printf("write success bytes:%d\n", ret);
    printf("now buffer data:%d, free:%d\n", buffer.getDataSize(), buffer.getFreeSize());

    char rb[64] = {0};
    printf("want read 20 bytes.\n");
    ret = buffer.read(rb, 20);
    printf("read %d bytes ok.\n", ret);
    printf("buffer left data:%d, free:%d\n", buffer.getDataSize(), buffer.getFreeSize());
    printf("buffer now:\n");
    buffer.printBytesHex(0, 32);


    printf("will write 17 byte:%s \n", wb);
    ret = buffer.write(wb, 17);
    printf("write success bytes:%d\n", ret);
    printf("now buffer data:%d, free:%d\n", buffer.getDataSize(), buffer.getFreeSize());


    printf("will write 17 byte:%s \n", wb);
    ret = buffer.write(wb, 17);
    printf("write success bytes:%d\n", ret);
    printf("now buffer data:%d, free:%d\n", buffer.getDataSize(), buffer.getFreeSize());



    printf("want read 20 bytes.\n");
    ret = buffer.read(rb, 20);
    printf("read %d bytes ok.\n", ret);
    printf("buffer left data:%d, free:%d\n", buffer.getDataSize(), buffer.getFreeSize());
    printf("buffer now:\n");
    buffer.printBytesHex(0, 32);

    printf("want read 20 bytes.\n");
    ret = buffer.read(rb, 20);
    printf("read %d bytes ok.\n", ret);
    printf("buffer left data:%d, free:%d\n", buffer.getDataSize(), buffer.getFreeSize());
    printf("buffer now:\n");
    buffer.printBytesHex(0, 32);
}

void RingBuffer::testPtr()
{
    int ret = 0;
    RingBuffer buffer;
    //设置存储单元为sizeof(void*)Byte, 2^3=8个存储单元共sizeof(void*)Byte * 8 Bytes 
    if (0 != (ret = buffer.setBufferSizePower(3, sizeof(void*))))
    {
        printf("set buffer size failed, ret:%d\n", ret);
    }

    test_t test[] = {
        {"n0",},
        {"n1",},
        {"n2",},
        {"n3",},
    };
    test_t* wb[] = {
        &test[0],
        &test[1],
        &test[2],
        &test[3],
    };
    test_t var_test = {"var"};
    test_t *ptr_test = new test_t();
        ptr_test->name = "ptr";

    printf("buffer size:%d\n", buffer.getBufferSize());
    printf("wb:\n");
    buffer.printTestPtr(4, wb);
    printf("will write 4:[n0,n3] \n");
    ret = buffer.write(wb, 4);
    printf("write success bytes:%d\n", ret);
    ret = buffer.write(&ptr_test, 1);
    printf("write success bytes:%d\n", ret);
    ptr_test = &var_test;
    ret = buffer.write(&ptr_test, 1);
    printf("write success bytes:%d\n", ret);
    printf("now buffer data:%d, free:%d\n", buffer.getDataSize(), buffer.getFreeSize());
    printf("buffer now:\n");
    buffer.printTestPtr(buffer.getBufferSize() + 1);

    test_t* rb[10] = {0};
    printf("want read 20 bytes.\n");
    ret = buffer.read(rb, 20);
    printf("read %d bytes ok.\n", ret);
    printf("buffer left data:%d, free:%d\n", buffer.getDataSize(), buffer.getFreeSize());
    printf("buffer rb:\n");
    buffer.printTestPtr(ret, rb);

    
    printf("will write 4:[n0,n3] \n");
    ret = buffer.write(wb, 4);
    printf("buffer now:\n");
    buffer.printTestPtr(buffer.getBufferSize() + 1);
}

void RingBuffer::testStruct()
{
    int ret = 0;
    RingBuffer buffer;
    //设置存储单元为sizeof(void*)Byte, 2^3=8个存储单元共sizeof(void*)Byte * 8 Bytes 
    if (0 != (ret = buffer.setBufferSizePower(3, sizeof(test_t))))
    {
        printf("set buffer size failed, ret:%d\n", ret);
    }

    test_t wb[] = {
        {"n0",},
        {"n1",},
        {"n2",},
        {"n3",},
    };

    test_t var_test = {"var"};
    test_t *ptr_test = new test_t();
        ptr_test->name = "ptr";

    printf("buffer size:%d\n", buffer.getBufferSize());
    printf("wb:\n");
    buffer.printTestStruct(4, wb);
    printf("will write 4:[n0,n3] \n");
    ret = buffer.write(wb, 4);
    printf("write success bytes:%d\n", ret);
    ret = buffer.write(ptr_test, 1);
    printf("write success bytes:%d\n", ret);
    ret = buffer.write(&var_test, 1);
    printf("write success bytes:%d\n", ret);
    printf("now buffer data:%d, free:%d\n", buffer.getDataSize(), buffer.getFreeSize());
    printf("buffer now:\n");
    buffer.printTestStruct(buffer.getBufferSize() + 1);

    test_t rb[10] = {0};
    printf("want read 20 bytes.\n");
    ret = buffer.read(rb, 20);
    printf("read %d bytes ok.\n", ret);
    printf("buffer left data:%d, free:%d\n", buffer.getDataSize(), buffer.getFreeSize());
    printf("buffer rb:\n");
    buffer.printTestStruct(ret, rb);

    
    printf("will write 4:[n0,n3] \n");
    ret = buffer.write(wb, 4);
    printf("buffer now:\n");
    buffer.printTestStruct(buffer.getBufferSize() + 1);

    printf("will read one to var.\n");
    test_t r_var;
    ret = buffer.read(&r_var, 1);
    printf("r_var:%s\n", r_var.name);
    printf("will read one to var.\n");
    r_var;
    ret = buffer.read(&r_var, 1);
    printf("r_var:%s\n", r_var.name);
}

int main(void)
{
    //RingBuffer::testByte();
    //RingBuffer::testPtr();
    RingBuffer::testStruct();
    return 0;
}